/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "MPM.h"

#include "core/设备内存缓存.h"
#include "core/引擎配置.h"
#include "物体/物体.h"
#include "面/面.h"


S_PhysicsMPM::S_PhysicsMPM(S_设备环境& ctx, std::wstring name) {
	m_IdType = E_物理引擎::E_物理引擎_MPM;

	std::vector<S_着色器创建参数> 参数配置 = {
		//{DEF_BINDING_topLAS, E_着色阶段::e_计算着色, E_板载缓存类型::e_光追BVH},
	};

	std::vector<S_常量推送创建参数> 常量 = {
		{E_着色阶段::e_计算着色, 0, sizeof(S_MPM_PTM_ConstPush)},
	};

	std::vector<S_常量推送创建参数> 网格参数初始化_常量 = {
		{E_着色阶段::e_计算着色, 0, sizeof(S_MPM_PTM_ConstPush)},
	};

	m_GPU计算_网格初始化 = f_df_创建并行计算(ctx, S_引擎配置::m_3D着色器文件根路径 + "网格参数初始化.spv", 参数配置, 网格参数初始化_常量);
	m_GPU计算_粒子赋予到网格 = f_df_创建并行计算(ctx, S_引擎配置::m_3D着色器文件根路径 + "粒子更新到网格.spv", 参数配置, 常量);
	m_GPU计算_网格更新 = f_df_创建并行计算(ctx, S_引擎配置::m_3D着色器文件根路径 + "网格更新.spv", 参数配置, 网格参数初始化_常量);
	m_GPU计算_网格更新到粒子 = f_df_创建并行计算(ctx, S_引擎配置::m_3D着色器文件根路径 + "网格更新到粒子.spv", 参数配置, 常量);


	m_域偏移 = {};
	m_网格分辨率 = {};
	m_网格单元大小 = 0;
}

S_PhysicsMPM::~S_PhysicsMPM() {
	f_bm_erase(m_坐标);
	f_bm_erase(m_速度);
	f_bm_erase(m_质量);
	//f_buf_erase(m_坐标);
	f_bm_erase(m_网格速度);
	f_bm_erase(m_网格质量);
}

void S_PhysicsMPM::f_Update() {

}

void S_PhysicsMPM::f_粒子施加力() {
	uint32 num = m_速度.m_Mem.m_数量;

	auto p = f_buf_Vec3_ptr(m_坐标);
	auto v = f_buf_Vec4_ptr(m_速度);
	for (uint32 i = 0; i < num; ++i) {
		v[i] += vec4{0, -9.8*0.0166, 0, 0};
		v[i] *= 0.5;

		//p[i] += v[i] * 0.016;
		//if(p[i].x < m_域偏移.x) p[i].x -= p[i].x - m_域偏移.x;
		//if(p[i].y < m_域偏移.y) p[i].y -= p[i].y - m_域偏移.y;
		//if(p[i].z < m_域偏移.z) p[i].z -= p[i].z - m_域偏移.z;
	}

	S_MPM_Grid_ConstPush 网格参数;
	网格参数.m_Address_weigth = f_buf_getOffsetAddress(m_网格质量);
	网格参数.m_Address_momentum = f_buf_getOffsetAddress(m_网格速度);
	网格参数.m_dim = _iVec3(m_网格分辨率);

	f_GPU_run计算(m_GPU计算_网格初始化, m_网格分辨率, &网格参数, sizeof(S_MPM_Grid_ConstPush));
}

void S_PhysicsMPM::f_粒子赋予到网格() {
	uint32 num = m_速度.m_Mem.m_数量;

	auto pv = f_buf_Vec3_ptr(m_坐标);
	for (uint32 i = 0; i < num; ++i) {
		
		ivec3 网格坐标 = vec_Min(_iVec3((pv[i] - m_域偏移) / m_网格单元大小), m_网格分辨率);
		网格坐标 = vec_Max(网格坐标, ivec3{0,0,0});
		网格坐标 = vec_Min(网格坐标, m_网格分辨率 - 1);

		uint32 index = f_glsl_CoordToIndex(_uVec3(网格坐标), m_网格分辨率);
		//float32 d = length(pv[i] - 网格坐标);
		//float32 w = d*d;
		vec3 dis = pv[i] - (_Vec3(网格坐标) * m_网格单元大小);
		float32 w = f_glsl_bspline(dis, m_网格单元大小*3);
	}


	S_MPM_PTM_ConstPush GPU参数;
	GPU参数.m_Address_particle = f_buf_getOffsetAddress(m_坐标);
	GPU参数.m_Address_particle_mass = f_buf_getOffsetAddress(m_质量);
	GPU参数.m_Address_particle_velocity = f_buf_getOffsetAddress(m_速度);

	GPU参数.m_Address_weigth = f_buf_getOffsetAddress(m_网格质量);
	GPU参数.m_Address_momentum = f_buf_getOffsetAddress(m_网格速度);

	GPU参数.m_dim = _iVec3(m_网格分辨率);
	GPU参数.m_gridOffset = m_域偏移;
	GPU参数.m_cellSize = m_网格单元大小;
	GPU参数.m_dt = 1.0/60.0;

	f_GPU_run计算(m_GPU计算_粒子赋予到网格, { num/512, 1, 1 }, &GPU参数, sizeof(S_MPM_PTM_ConstPush));


	//auto w = f_buf_F32_ptr(m_网格质量);
	//uint32 层 = m_网格分辨率.z * m_网格分辨率.y;
	//for (uint32 z = 0; z < m_网格分辨率.z; ++z) {
	//	for (uint32 y = 0; y < m_网格分辨率.y; ++y) {
	//		for (uint32 x = 0; x < m_网格分辨率.x; ++x) {
	//			uint32 index = 层 * z + y * m_网格分辨率.x + x;
	//			std::cout<<w[index]<<std::endl;
	//		}
	//	}
	//}


}

void S_PhysicsMPM::f_网格解算() {
	
	S_MPM_Grid_ConstPush 网格参数;
	网格参数.m_Address_weigth = f_buf_getOffsetAddress(m_网格质量);
	网格参数.m_Address_momentum = f_buf_getOffsetAddress(m_网格速度);
	网格参数.m_dim = _iVec3(m_网格分辨率);

	f_GPU_run计算(m_GPU计算_网格更新, m_网格分辨率, &网格参数, sizeof(S_MPM_Grid_ConstPush));

	//uint32 层 = m_网格分辨率.z * m_网格分辨率.y;
	//for (uint32 z = 0; z < m_网格分辨率.z; ++z) {
	//	for (uint32 y = 0; y < m_网格分辨率.y; ++y) {
	//		for (uint32 x = 0; x < m_网格分辨率.x; ++x) {
	//			uint32 index = 层 * z + y * m_网格分辨率.x + x;
	//		}
	//	}
	//}
}

void S_PhysicsMPM::f_网格更新到粒子() {
	uint32 num = m_速度.m_Mem.m_数量;
	//auto px = f_buf_Vec3_ptr(m_坐标);
	auto pv = f_buf_Vec3_ptr(m_速度);

	
	S_MPM_PTM_ConstPush GPU参数;
	GPU参数.m_Address_particle = f_buf_getOffsetAddress(m_坐标);
	GPU参数.m_Address_particle_mass = f_buf_getOffsetAddress(m_质量);
	GPU参数.m_Address_particle_velocity = f_buf_getOffsetAddress(m_速度);

	GPU参数.m_Address_weigth = f_buf_getOffsetAddress(m_网格质量);
	GPU参数.m_Address_momentum = f_buf_getOffsetAddress(m_网格速度);

	GPU参数.m_dim = _iVec3(m_网格分辨率);
	GPU参数.m_gridOffset = m_域偏移;
	GPU参数.m_cellSize = m_网格单元大小;
	GPU参数.m_dt = 1.0 / 60.0;

	uint32 x = num / 512;
	f_GPU_run计算(m_GPU计算_网格更新到粒子, {x, 512, 1}, &GPU参数, sizeof(S_MPM_PTM_ConstPush));

	//for (uint32 i = 0; i < num; ++i) {
	//	std::cout<<pv[i].x<<std::endl;
	//}


}



S_Physics* f_phy_创建MPM(S_设备环境& ctx) {
	S_PhysicsMPM* phy = new S_PhysicsMPM(ctx);

	phy->m_坐标 = f_bm_alloc(f_buf_getGlobal().g_MPM_坐标, 0);
	phy->m_速度 = f_bm_alloc(f_buf_getGlobal().g_PHY_速度和年龄, 0);
	phy->m_质量 = f_bm_alloc(f_buf_getGlobal().g_MPM_密度_lambda, 0);
	phy->m_速度梯度 = f_bm_alloc(f_buf_getGlobal().g_MPM_速度梯度, 0);

	phy->m_网格速度 = f_bm_alloc(f_buf_getGlobal().g_MPM_网格速度, 0);
	phy->m_网格质量 = f_bm_alloc(f_buf_getGlobal().g_MPM_网格密度, 0);

	return phy;
}

void f_phy_销毁MPM(S_Physics* phy) {
	delete phy;
}

void f_mpm_重置(S_PhysicsMPM& mpm) {
	f_bm_resize(mpm.m_坐标, 0);
	f_bm_resize(mpm.m_速度, 0);
	f_bm_resize(mpm.m_质量, 0);

	//f_gbuf_resize(mpm.m_网格速度_原子负, 0);
}

void f_mpm_设置MPM网格维度(S_Physics* phy, const vec3& 网格大小, const vec3& 域偏移, float32 单元大小) {
	S_PhysicsMPM& mpm = *dynamic_cast<S_PhysicsMPM*>(phy);

	mpm.m_域偏移 = 域偏移 - (网格大小/2);
	mpm.m_网格单元大小 = 单元大小;
	mpm.m_网格分辨率 = _uVec3(网格大小 / 单元大小);

	uint64 count = mpm.m_网格分辨率.x * mpm.m_网格分辨率.y * mpm.m_网格分辨率.z;

	f_bm_resize(mpm.m_网格速度, count);
	f_bm_resize(mpm.m_网格质量, count);
}

void f_mpm_添加物理体(S_Physics* phy, S_PhyBodyArray* body) {
	S_PhysicsMPM& mpm = *dynamic_cast<S_PhysicsMPM*>(phy);

	for (uint32 i = 0; i < body->count; ++i) {
		auto& 物理体 = body->ptr_userData[i];

		switch (物理体->m_物理体类型) {
			case E_物理体类型::E_物理体_静态: {

				break;
			}
			default: {
				auto* ob = ((S_物体*)物理体->m_几何体->m_绑定网格物体);
				if(!ob) continue;

				auto me = f_ob_getMesh((S_物体*)物理体->m_几何体->m_绑定网格物体, E_物体网格元素类型::e_MT_面);

				std::vector<vec3> 体素坐标;
				//f_fromMesh创建体素(me, f_ob_get独立计算变换矩阵(ob), 物理体->m_密度, 体素坐标);
				f_fromMesh创建体素(me, f_ob_get变换矩阵(ob, ob->m_实例ID), mpm.m_网格单元大小 * 0.6, 体素坐标);

				std::vector<vec3> 体素速度(体素坐标.size());
				std::vector<vec2> 体素质量(体素坐标.size(), {0.1,0.1});

				f_buf_push_back(mpm.m_坐标, 体素坐标);
				f_buf_push_back(mpm.m_速度, 体素速度);
				f_buf_push_back(mpm.m_质量, 体素质量);


				break;

			}
		}
	}

	std::vector<vec3> 体素坐标(512);
	std::vector<vec3> 体素速度(512);
	std::vector<vec2> 体素密度(512);
	f_buf_push_back(mpm.m_坐标, 体素坐标);
	f_buf_push_back(mpm.m_速度, 体素速度);
	f_buf_push_back(mpm.m_质量, 体素密度);
}

void f_mpm_解算(S_PhysicsMPM* mpm, float32 时间步进) {
	mpm->f_粒子施加力();
	mpm->f_粒子赋予到网格();
	mpm->f_网格解算();
	mpm->f_网格更新到粒子();

}

void f_mpm_取调试粒子(S_Physics* phy, S_物体* ob) {
	S_PhysicsMPM& mpm = *dynamic_cast<S_PhysicsMPM*>(phy);

	f_mesh_fill顶点数据(f_ob_getMesh(ob, 0), mpm.m_坐标, mpm.m_速度, mpm.m_质量);

}





